/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package edu.hd4ic.gui.background;

import edu.hd4ic.algorithm.base.HDBasedAlgorithm;
import edu.hd4ic.algorithm.base.HDValue;

import java.awt.Image;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.*;
import java.util.concurrent.ExecutionException;
import javax.imageio.ImageIO;
import javax.swing.SwingWorker;

import edu.hd4ic.edu.hd4ic.data.ProcessingImageDataContainer;
import org.apache.commons.io.FileDeleteStrategy;
import org.apache.log4j.Logger;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;

/**
 * @author morfant
 */
public class BackGroundSwingWorker extends SwingWorker<List<HDValue>, List<HDValue>> {

    private static final Logger LOGGER = Logger.getLogger(BackGroundSwingWorker.class);
    private static final Logger PROFILER_LOGGER = Logger.getLogger("profiler");
    private Workbook workbook;
    private Sheet mainSheet;
    private HDBasedAlgorithm hdBasedAlgorithm;
    private Map<String, ProcessingImageDataContainer> inputImageFilePathAndItsDataContainerMap =
            new HashMap<String, ProcessingImageDataContainer>();
    private Map<String, ProcessingImageDataContainer> templateImageFilePathAndItsDataContainerMap =
            new HashMap<String, ProcessingImageDataContainer>();
    private HDValuesPresenter hdValuePresenter;
    private double calculationThreshold;

    public BackGroundSwingWorker(HDBasedAlgorithm hdBasedAlgorithm,
                                 double calcuationThreshold,
                                 Map<String, ProcessingImageDataContainer> inputImageFilePathAndItsDataContainerMap,
                                 Map<String, ProcessingImageDataContainer> templateImageFilePathAndItsDataContainerMap,
                                 HDValuesPresenter hdValuesPresenter) {
        this.hdBasedAlgorithm = hdBasedAlgorithm;
        this.calculationThreshold = calcuationThreshold;
        this.inputImageFilePathAndItsDataContainerMap = inputImageFilePathAndItsDataContainerMap;
        this.templateImageFilePathAndItsDataContainerMap = templateImageFilePathAndItsDataContainerMap;
        this.hdValuePresenter = hdValuesPresenter;
        this.workbook = new XSSFWorkbook();
        this.mainSheet = workbook.createSheet("Main");
    }

    private void addInputAndTemplateImageName(String inputImageName, String templateImageName, List<HDValue> listOfHDValues) {
        for (HDValue hdValue : listOfHDValues) {
            hdValue.setInputImageName(inputImageName);
            hdValue.setTemplateImageName(templateImageName);
        }
    }

    @Override
    protected List<HDValue> doInBackground() throws Exception {
        List<HDValue> resultOfComputation = new LinkedList<HDValue>();
        long startTime, executionTime, inputImageProcessingTime;

        ProcessingImageDataContainer inputImageDataContainer, templateImageDataContainer;
        List<HDValue> listOfHDValues;

        int rowNumber = 0;
        Row row;

        for (String inputImageName : inputImageFilePathAndItsDataContainerMap.keySet()) {
            inputImageDataContainer = inputImageFilePathAndItsDataContainerMap.get(inputImageName);
            row = mainSheet.createRow(rowNumber);
            row.createCell(0).setCellValue(inputImageName);
            rowNumber++;
            for (String templateImageName : templateImageFilePathAndItsDataContainerMap.keySet()) {
                try {
                    templateImageDataContainer = templateImageFilePathAndItsDataContainerMap.get(templateImageName);
                    startTime = System.currentTimeMillis();
                    listOfHDValues = hdBasedAlgorithm.
                            compareImage(inputImageDataContainer,
                                    templateImageDataContainer,
                                    calculationThreshold);
                    executionTime = System.currentTimeMillis() - startTime;
                    PROFILER_LOGGER.debug("Время выполнения равно = " + executionTime);
                    row = mainSheet.createRow(rowNumber);
                    row.createCell(0).setCellValue(templateImageName);
                    row.createCell(1).setCellValue(executionTime);
                    rowNumber++;
                    addInputAndTemplateImageName(inputImageName, templateImageName, listOfHDValues);
                    listOfHDValues = processComputationResults(listOfHDValues);
                    resultOfComputation.addAll(listOfHDValues);
                    LOGGER.debug("Compare image = " + inputImageName + " with template = " + templateImageName + ".");
                } catch (Exception exception) {
                    LOGGER.debug("Проблемы при сравнении изображений!", exception);
                }
            }
            publish(resultOfComputation);
            resultOfComputation = new LinkedList<HDValue>();
        }

        publishProfilingResult();
        return resultOfComputation;
    }

    private void publishProfilingResult() {
        try {
            FileOutputStream outputStream = new FileOutputStream("results/Profiler" + System.currentTimeMillis() + ".xlsx");
            workbook.write(outputStream);
            outputStream.flush();
            outputStream.close();
        } catch (IOException e) {
            e.printStackTrace();  //To change body of catch statement use File | Settings | File Templates.
        }
    }

    private List<HDValue> processComputationResults(List<HDValue> listOfHDValues) {
        List<HDValue> resultList = new LinkedList<HDValue>();
        HDValue currentHDValue = null;

        int x, y;
        int previousX = 0;
        int previousY = 0;
        double minValueForCurrentHDValue = Double.MAX_VALUE;
        for (HDValue hdValue : listOfHDValues) {
            x = hdValue.getX();
            y = hdValue.getY();
            if ((previousX + 1 == x) || (previousY + 1 == y)) {
                if (minValueForCurrentHDValue > hdValue.getHdValue()) {
                    currentHDValue = hdValue;
                    minValueForCurrentHDValue = hdValue.getHdValue();
                }
            } else {
                if (currentHDValue != null) {
                    resultList.add(currentHDValue);
                }
                currentHDValue = hdValue;
                minValueForCurrentHDValue = hdValue.getHdValue();
            }
            previousX = x;
            previousY = y;
        }

        if (currentHDValue != null) {
            resultList.add(currentHDValue);
        }

        return resultList;
    }

    @Override
    protected void done() {
        ((DefaultHDValuesPresenter) hdValuePresenter).endShow();
    }

    @Override
    protected void process(List<List<HDValue>> chunks) {
        for (List<HDValue> listOfHDValue : chunks) {
            hdValuePresenter.showHDValues(listOfHDValue);
        }
    }
}
